Embryonic mouse #8 E14.5 wild type

supplementary

Smartseq2 method. reads aligned to mm10-plus.

Read the gene cell table that has the read_count for every gene and cell:
setwd("/Volumes/GoogleDrive/My Drive/research/Mu_He/sequencing")
Trachea_May<-read.csv(file="180516_NS500126_0797_AHMCKKBGX5.csv",header=TRUE,sep=",") 
Remove the first column (gene names), and convert the gene names to rownames of the dataframe
dfTrachea_May<-as.data.frame(Trachea_May[,-1]) 
rownames(dfTrachea_May)<-Trachea_May[,1]
Remove the last column (“undetermined” reads)
dfTrachea_May<-dfTrachea_May[,-705] #remove the "undetermined" column
got a dataframe of 704 variables (columns),because we have 2 plates each have 352 “cells”. Each of the column in the dataframe is a cell
Also this dataframe has 23438 observations (rows), each of which is a gene
library(dplyr)
package ‘dplyr’ was built under R version 3.4.4
Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
Specify the rawdata to be taken by Seurat:
raw.data<-dfTrachea_May
analyze ERCC:
get all rownames that contain “ERCC”:
erccs <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = TRUE)
calculate the percentage of ERCC reads in total reads for each cell, and plot:
percent.ercc <- Matrix::colSums(raw.data[erccs, ])/Matrix::colSums(raw.data)
df_ercc<-as.data.frame(cbind(colnames(raw.data),as.numeric(percent.ercc)))
ggplot(df_ercc,aes(percent.ercc))+geom_density()
Get the row index for ERCCs:
ercc.index <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = FALSE)
remove ERCCs from the dataset (but the percent.ERCC will be kept as a metadata column):
raw.data <- raw.data[-ercc.index,]
Now create seurat object.
seuTrachea_May <- CreateSeuratObject(raw.data = raw.data, project = "Trachea_May_mouse8", 
                                 min.cells = 1, min.genes = 500)
dim(seuTrachea_May@raw.data)
So I have 523 “cells” in which at least 500 genes are detected. 18157 “genes” are detected in at least 1 “cell”
Add some meta data to the seurat object:
seuTrachea_May <- AddMetaData(object = seuTrachea_May, percent.ercc, col.name = "percent.ercc")

#seurat was written for drop-seq/10X, in which nUMI is used for quantification. We use number of reads for quantification instead:
colnames(seuTrachea_May@meta.data)[colnames(seuTrachea_May@meta.data) == 'nUMI'] <- 'nReads'
Now analyze ribosome genes:
generate a list of ribo gene names:
ribo.genes <- grep(pattern = "^Rp[sl][[:digit:]]", x = rownames(x = seuTrachea_May@data), value = TRUE)
calculate their ratio for every cell:
percent.ribo <- Matrix::colSums(seuTrachea_May@raw.data[ribo.genes, ])/Matrix::colSums(seuTrachea_May@raw.data)
Now add a column for percent.ribo as metadata:
seuTrachea_May <- AddMetaData(object = seuTrachea_May, metadata = percent.ribo, col.name = "percent.ribo")
sanity check:
VlnPlot(object = seuTrachea_May, features.plot = c("nGene", "nReads", "percent.ercc","percent.ribo"), nCol = 4,x.lab.rot = TRUE)
GenePlot(object = seuTrachea_May, gene1 = "nReads", gene2 = "nGene", use.raw=T)
Now remove the cells with too few reads <100k and too few genes <500
seuTrachea_May <- FilterCells(object = seuTrachea_May, subset.names = c("nGene", "nReads"), 
                          low.thresholds = c(500, 100000), high.thresholds = c(Inf, Inf))
dim(seuTrachea_May@data)
Now normalize the gene expression measurements for each cell by the total expression (so it is # of reads for this gene divided by nReads for that cell), multiply this by a scale factor (10,000 by default), log-transform (log1p(x), which is log(1+x)) the result, and then save the result is in SNr_Mar@data
seuTrachea_May <- NormalizeData(object = seuTrachea_May)
Now scale the data: The scale.data slot (object@scale.data) represents a cell’s relative expression of each gene, in comparison to all other cells. So value 0 in the scale.data means average expression level for that gene across all cells. The more positive, the higher that gene is expressed in that cell. The values are re-centered for each gene. This data is used as input for dimensional reduction techniques, and is displayed in heatmaps.
#if want to regress out some factors, use in the ScaleData function: vars.to.regress = c("nReads", "percent.ercc","Rn45s","nGene")
#Here let's not regress out anything and take a look
seuTrachea_May <- ScaleData(object = seuTrachea_May)
seuTrachea_May <- FindVariableGenes(object = seuTrachea_May, do.plot = TRUE, x.high.cutoff = Inf, y.cutoff = 0.5)
The above generats object@var.genes, which is a vector of gene names that are identified to be variable. y.cutoff decides the cutoff for being “variable”.
The result of all analysis is stored in object@hvg.info. A plot is also generated, with “variable” genes labeled with names.
run PCA on the set of genes decided in so_SNr@var.genes:
Returns Seurat object with the PCA calculation stored in object@dr$pca. In the function below, if do.print=TRUE, genes in each PC will be shown.
seuTrachea_May <- RunPCA(object = seuTrachea_May, do.print = FALSE)
PCAPlot(seuTrachea_May)
ProjectPCA scores each gene in the dataset (including genes not included in the PCA) based on their correlation with the calculated components. Though we don’t use this further here, it can be used to identify markers that are strongly correlated with cellular heterogeneity, but may not have passed through variable gene selection. The results of the projected PCA can be explored by setting use.full=T in the functions below.
seuTrachea_May <- ProjectPCA(object = seuTrachea_May, do.print = TRUE)
Another way to show major genes in major PCs:
PrintPCA(seuTrachea_May, pcs.print = 1:5, genes.print = 5, use.full = TRUE)
Below is another way to see PCs and how they separate the data: cells and genes are ordered according to their PCA scores. Setting cells.use (for example: cell.use=100) to a number plots the ‘extreme’ cells on both ends of the spectrum, which dramatically speeds plotting for large datasets (but will ignore the cells in the middle). num.genes=30 by default.
PCHeatmap(object = seuTrachea_May, pc.use = 1:3, do.balanced = TRUE, label.columns = FALSE)
Now need to decide how many PCs to use:
PCElbowPlot(object = seuTrachea_May)
The above plot shows that the elbow of the graph falls at around pc 20.
Another way to statistically estimate: (caution: running this is slow)
seuTrachea_May <- JackStraw(seuTrachea_May, num.replicate = 100, do.print = FALSE)
JackStrawPlot(seuTrachea_May, PCs = 1:20)
n.pcs = 20
resolution parameter sets the ‘granularity’ of the downstream clustering, with increased values leading to a greater number of clusters.
res.used <- 1
K-nearest neighbor:
seuTrachea_May <- FindClusters(object = seuTrachea_May, reduction.type = "pca", dims.use = 1:n.pcs, 
                     resolution = res.used, print.output = 0, force.recalc = T)
Let’s extract plate and index information from the cell names (column names) and make them part of the meta data
cell_name<-read.table(text=names(seuTrachea_May@ident),sep="_",colClasses = "character")
table(cell_name[,1])

B003935 B003938 
    309     203 
colnames(cell_name)<-c("plate","well","tissue","other")
Now I can see how many cell passing filters from each plate.
Now let’s make the “plate” information part of each cell’s metadata:
plate<-cell_name$plate
names(plate)<-names(seuTrachea_May@ident)   #AddMetaData needs names to assign values
seuTrachea_May<-AddMetaData(object = seuTrachea_May, metadata = plate, col.name = "plate")
tSNE: (perplexity default is 30)
seuTrachea_May <- RunTSNE(object = seuTrachea_May, dims.use = 1:n.pcs, perplexity=30)
TSNEPlot(object = seuTrachea_May, do.label = T)
TSNEPlot(object = seuTrachea_May, group.by="plate")
FeaturePlot(seuTrachea_May, c("nGene","Gfp_transgene","Tdtom_transgene","Shh","Ano1","Epcam","Lum","Aurkb","Matn4","Esam","Actc1","Pax8"), pt.size = 0.9, nCol = 3,no.legend = F)
seuTrachea_May <- SetAllIdent(object = seuTrachea_May, id = "ident")
GenePlot(object = seuTrachea_May, gene1 = "Shh", gene2 = "Gfp_transgene", use.raw=T)
VlnPlot(object = seuTrachea_May, features.plot = c("Gfp_transgene","Tdtom_transgene", "Cre_transgene"), nCol = 3)
DoHeatmap(object = seuTrachea_May, genes.use = c("Tdtom_transgene","Cre_transgene", "Gfp_transgene","Shh","Ano1","Sox9"), 
    slim.col.label = TRUE, group.label.rot = TRUE)
find markers for every cluster compared to all remaining cells, report only the positive ones
cluster.markers <- FindAllMarkers(object=seuTrachea_May, min.pct = 0.2,only.pos=TRUE)
cluster.markers %>% group_by(cluster) %>% top_n(10, avg_logFC)
compare cluster 0 and 2
cluster0.markers.pos <- FindMarkers(seuTrachea_May, ident.1 = 0,ident.2 = 2, min.pct = 0,only.pos=TRUE)
print(cluster0.markers.pos)
cluster2.markers.pos <- FindMarkers(seuTrachea_May, ident.1 = 2,ident.2 = 0, min.pct = 0,only.pos=TRUE)
print(cluster2.markers.pos)
save the seurat project for future visit:
save(seuTrachea_May,file="seurat_Trachea_May.RData")
load("seurat_Trachea_May.RData")

Map sorting data to sequencing data:

Read index data:
B003938<-read.csv(file="Trachea_B003938.csv",header=TRUE,sep=",",stringsAsFactors = F)
B003938_sort<-B003938[B003938$Index!="",]
B003935<-read.csv(file="Trachea_B003935.csv",header=TRUE,sep=",",stringsAsFactors = F)
B003935_sort<-B003935[B003935$Index!="",]
Extract expression levels of genes. Make a dataframe (cluster_cell) that has the plate #, index#, cluster identity, and expression levels of some genes
Tdtomato<-seuTrachea_May@data[which(rownames(seuTrachea_May@data)=="Tdtom_transgene"),]
Gfp<-seuTrachea_May@data[which(rownames(seuTrachea_May@data)=="Gfp_transgene"),]
cluster_cell<-cbind(cell_name[,1:2],seuTrachea_May@ident,Tdtomato,Gfp)
colnames(cluster_cell)<-c("plate","Index","identity","Tdtom_transgene","Gfp_transgene")
specify plate# in sorting metadata
B003935_sort$plate<-rep("B003935",352)
#merge_B003935<-merge(cluster_cell,B003935_sort)
#lowQ_B003935 <- anti_join(B003935_sort,cluster_cell,by=c("plate","Index"))
join_B003935<-left_join(B003935_sort,cluster_cell)
Joining, by = c("Index", "plate")
table(join_B003935$identity,exclude=NULL)

   0    1    2    3    4    5    6 <NA> 
  50   90   81   59   11    7   11   43 
NA in the identity column means those “cells” did not pass the filtering criteria above (nGene 500, nReads 100k etc..)
ggplot(join_B003935,aes(x=log10(Hoechst.33342.A.Compensated)))+geom_density(aes(color=identity))

So those Hoechst super high junk tend to have intermediate-high level of EGFP:
ggplot(join_B003935,aes(x=log10(Hoechst.33342.A.Compensated),y=log10(EGFP.A.Compensated)))+geom_point(aes(color=identity))
And the Hoechst super high junk tend to have relatively low tdTomato signal:
ggplot(join_B003935,aes(x=log10(Hoechst.33342.A.Compensated),y=log10(tdTomato.A.Compensated)))+geom_point(aes(color=identity))

And the NA “cells”" tends to be very small in terms of FSC.W:
ggplot(join_B003935,aes(log10(EGFP.A.Compensated),FSC.W))+geom_point(aes(color=identity))

ggplot(join_B003935,aes(log10(tdTomato.A.Compensated),FSC.W))+geom_point(aes(color=identity))
ggplot(join_B003935,aes(FSC.A,log10(BSC.A)))+geom_point(aes(color=identity))
ggplot(join_B003935,aes(FSC.A,log10(Hoechst.33342.A.Compensated)))+geom_point(aes(color=identity))

Insterestingly cluster 0 and 2 may differ a bit in sizes
ggplot(join_B003935[join_B003935$identity %in% c("0","2"),],aes(FSC.W))+geom_density(aes(color=identity))
B003938_sort$plate<-rep("B003938",352)
join_B003938<-left_join(B003938_sort,cluster_cell)
Joining, by = c("Index", "plate")
table(join_B003938$identity,exclude=NULL)

   0    1    2    3    4    5    6 <NA> 
  68   28   19    5   50   22   11  149 
Intermediate Hoechst and below were cut off. Hoechst super high were sorted. Therefore we got so many NA in B003938
ggplot(join_B003938,aes(log10(Hoechst.33342.A.Compensated)))+geom_density(aes(color=identity))
Again those Hoechst high junk is small in size

ggplot(join_B003938,aes(x=log10(EGFP.A.Compensated),y=log10(tdTomato.A.Compensated),color=Gfp_transgene))+geom_point(size=0.3)+scale_color_continuous(low="yellow",high="red")

ggplot(join_B003938,aes(x=log10(EGFP.A.Compensated),y=log10(tdTomato.A.Compensated),color=Tdtom_transgene))+geom_point(size=0.3)+scale_color_continuous(low="yellow",high="red")

ggplot(join_B003938,aes(log10(EGFP.A.Compensated),FSC.W))+geom_point(aes(color=identity))
ggplot(join_B003938,aes(log10(tdTomato.A.Compensated),FSC.W))+geom_point(aes(color=identity))
ggplot(join_B003938,aes(FSC.A,log10(Hoechst.33342.A.Compensated)))+geom_point(aes(color=identity))
LS0tCnRpdGxlOiAiVHJhY2hlYSBzYW1wbGUgY29sbGVjdGVkIG9uIE1heSAzIDIwMTgiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyMjIyBFbWJyeW9uaWMgbW91c2UgIzggRTE0LjUgd2lsZCB0eXBlCiMjIyMgc3VwcGxlbWVudGFyeQojIyMjIFNtYXJ0c2VxMiBtZXRob2QuIHJlYWRzIGFsaWduZWQgdG8gbW0xMC1wbHVzLgojIyMjI1JlYWQgdGhlIGdlbmUgY2VsbCB0YWJsZSB0aGF0IGhhcyB0aGUgcmVhZF9jb3VudCBmb3IgZXZlcnkgZ2VuZSBhbmQgY2VsbDoKYGBge3J9CnNldHdkKCIvVm9sdW1lcy9Hb29nbGVEcml2ZS9NeSBEcml2ZS9yZXNlYXJjaC9NdV9IZS9zZXF1ZW5jaW5nIikKVHJhY2hlYV9NYXk8LXJlYWQuY3N2KGZpbGU9IjE4MDUxNl9OUzUwMDEyNl8wNzk3X0FITUNLS0JHWDUuY3N2IixoZWFkZXI9VFJVRSxzZXA9IiwiKSAKYGBgCiMjIyMjUmVtb3ZlIHRoZSBmaXJzdCBjb2x1bW4gKGdlbmUgbmFtZXMpLCBhbmQgY29udmVydCB0aGUgZ2VuZSBuYW1lcyB0byByb3duYW1lcyBvZiB0aGUgZGF0YWZyYW1lCmBgYHtyfQpkZlRyYWNoZWFfTWF5PC1hcy5kYXRhLmZyYW1lKFRyYWNoZWFfTWF5WywtMV0pIApyb3duYW1lcyhkZlRyYWNoZWFfTWF5KTwtVHJhY2hlYV9NYXlbLDFdCmBgYAojIyMjI1JlbW92ZSB0aGUgbGFzdCBjb2x1bW4gKCJ1bmRldGVybWluZWQiIHJlYWRzKQpgYGB7cn0KZGZUcmFjaGVhX01heTwtZGZUcmFjaGVhX01heVssLTcwNV0gI3JlbW92ZSB0aGUgInVuZGV0ZXJtaW5lZCIgY29sdW1uCmBgYAojIyMjI2dvdCBhIGRhdGFmcmFtZSBvZiA3MDQgdmFyaWFibGVzIChjb2x1bW5zKSxiZWNhdXNlIHdlIGhhdmUgMiBwbGF0ZXMgZWFjaCBoYXZlIDM1MiAiY2VsbHMiLiBFYWNoIG9mIHRoZSBjb2x1bW4gaW4gdGhlIGRhdGFmcmFtZSBpcyBhIGNlbGwKIyMjIyNBbHNvIHRoaXMgZGF0YWZyYW1lIGhhcyAyMzQzOCBvYnNlcnZhdGlvbnMgKHJvd3MpLCBlYWNoIG9mIHdoaWNoIGlzIGEgZ2VuZQoKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KE1hdHJpeCkKYGBgCiMjIyMjU3BlY2lmeSB0aGUgcmF3ZGF0YSB0byBiZSB0YWtlbiBieSBTZXVyYXQ6CgpgYGB7cn0KcmF3LmRhdGE8LWRmVHJhY2hlYV9NYXkKYGBgCgojIyMjI2FuYWx5emUgRVJDQzoKIyMjIyNnZXQgYWxsIHJvd25hbWVzIHRoYXQgY29udGFpbiAiRVJDQyI6CmBgYHtyfQplcmNjcyA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YSksIHZhbHVlID0gVFJVRSkKYGBgCgojIyMjI2NhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZSBvZiBFUkNDIHJlYWRzIGluIHRvdGFsIHJlYWRzIGZvciBlYWNoIGNlbGwsIGFuZCBwbG90OgpgYGB7cn0KcGVyY2VudC5lcmNjIDwtIE1hdHJpeDo6Y29sU3VtcyhyYXcuZGF0YVtlcmNjcywgXSkvTWF0cml4Ojpjb2xTdW1zKHJhdy5kYXRhKQpkZl9lcmNjPC1hcy5kYXRhLmZyYW1lKGNiaW5kKGNvbG5hbWVzKHJhdy5kYXRhKSxhcy5udW1lcmljKHBlcmNlbnQuZXJjYykpKQpnZ3Bsb3QoZGZfZXJjYyxhZXMocGVyY2VudC5lcmNjKSkrZ2VvbV9kZW5zaXR5KCkKYGBgCgojIyMjIyNHZXQgdGhlIHJvdyBpbmRleCBmb3IgRVJDQ3M6CmBgYHtyfQplcmNjLmluZGV4IDwtIGdyZXAocGF0dGVybiA9ICJeRVJDQy0iLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBGQUxTRSkKYGBgCgojIyMjIyNyZW1vdmUgRVJDQ3MgZnJvbSB0aGUgZGF0YXNldCAoYnV0IHRoZSBwZXJjZW50LkVSQ0Mgd2lsbCBiZSBrZXB0IGFzIGEgbWV0YWRhdGEgY29sdW1uKToKYGBge3J9CnJhdy5kYXRhIDwtIHJhdy5kYXRhWy1lcmNjLmluZGV4LF0KYGBgCgojIyMjI05vdyBjcmVhdGUgc2V1cmF0IG9iamVjdC4KYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIENyZWF0ZVNldXJhdE9iamVjdChyYXcuZGF0YSA9IHJhdy5kYXRhLCBwcm9qZWN0ID0gIlRyYWNoZWFfTWF5X21vdXNlOCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY2VsbHMgPSAxLCBtaW4uZ2VuZXMgPSA1MDApCmBgYApgYGB7cn0KZGltKHNldVRyYWNoZWFfTWF5QHJhdy5kYXRhKQpgYGAKIyMjIyNTbyBJIGhhdmUgNTIzICJjZWxscyIgaW4gd2hpY2ggYXQgbGVhc3QgNTAwIGdlbmVzIGFyZSBkZXRlY3RlZC4gMTgxNTcgImdlbmVzIiBhcmUgZGV0ZWN0ZWQgaW4gYXQgbGVhc3QgMSAiY2VsbCIKCiMjIyMjQWRkIHNvbWUgbWV0YSBkYXRhIHRvIHRoZSBzZXVyYXQgb2JqZWN0OgpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIHBlcmNlbnQuZXJjYywgY29sLm5hbWUgPSAicGVyY2VudC5lcmNjIikKCiNzZXVyYXQgd2FzIHdyaXR0ZW4gZm9yIGRyb3Atc2VxLzEwWCwgaW4gd2hpY2ggblVNSSBpcyB1c2VkIGZvciBxdWFudGlmaWNhdGlvbi4gV2UgdXNlIG51bWJlciBvZiByZWFkcyBmb3IgcXVhbnRpZmljYXRpb24gaW5zdGVhZDoKY29sbmFtZXMoc2V1VHJhY2hlYV9NYXlAbWV0YS5kYXRhKVtjb2xuYW1lcyhzZXVUcmFjaGVhX01heUBtZXRhLmRhdGEpID09ICduVU1JJ10gPC0gJ25SZWFkcycKYGBgCgojIyMjI05vdyBhbmFseXplIHJpYm9zb21lIGdlbmVzOgojIyMjIyNnZW5lcmF0ZSBhIGxpc3Qgb2YgcmlibyBnZW5lIG5hbWVzOgpgYGB7cn0Kcmliby5nZW5lcyA8LSBncmVwKHBhdHRlcm4gPSAiXlJwW3NsXVtbOmRpZ2l0Ol1dIiwgeCA9IHJvd25hbWVzKHggPSBzZXVUcmFjaGVhX01heUBkYXRhKSwgdmFsdWUgPSBUUlVFKQpgYGAKIyMjIyMjY2FsY3VsYXRlIHRoZWlyIHJhdGlvIGZvciBldmVyeSBjZWxsOgpgYGB7cn0KcGVyY2VudC5yaWJvIDwtIE1hdHJpeDo6Y29sU3VtcyhzZXVUcmFjaGVhX01heUByYXcuZGF0YVtyaWJvLmdlbmVzLCBdKS9NYXRyaXg6OmNvbFN1bXMoc2V1VHJhY2hlYV9NYXlAcmF3LmRhdGEpCmBgYAoKIyMjIyMjTm93IGFkZCBhIGNvbHVtbiBmb3IgcGVyY2VudC5yaWJvIGFzIG1ldGFkYXRhOgpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIG1ldGFkYXRhID0gcGVyY2VudC5yaWJvLCBjb2wubmFtZSA9ICJwZXJjZW50LnJpYm8iKQpgYGAKCiMjIyMjc2FuaXR5IGNoZWNrOgpgYGB7cn0KVmxuUGxvdChvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZmVhdHVyZXMucGxvdCA9IGMoIm5HZW5lIiwgIm5SZWFkcyIsICJwZXJjZW50LmVyY2MiLCJwZXJjZW50LnJpYm8iKSwgbkNvbCA9IDQseC5sYWIucm90ID0gVFJVRSkKYGBgCmBgYHtyfQpHZW5lUGxvdChvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZ2VuZTEgPSAiblJlYWRzIiwgZ2VuZTIgPSAibkdlbmUiLCB1c2UucmF3PVQpCmBgYAoKIyMjIyNOb3cgcmVtb3ZlIHRoZSBjZWxscyB3aXRoIHRvbyBmZXcgcmVhZHMgPDEwMGsgYW5kIHRvbyBmZXcgZ2VuZXMgPDUwMApgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gRmlsdGVyQ2VsbHMob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIHN1YnNldC5uYW1lcyA9IGMoIm5HZW5lIiwgIm5SZWFkcyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsb3cudGhyZXNob2xkcyA9IGMoNTAwLCAxMDAwMDApLCBoaWdoLnRocmVzaG9sZHMgPSBjKEluZiwgSW5mKSkKYGBgCmBgYHtyfQpkaW0oc2V1VHJhY2hlYV9NYXlAZGF0YSkKYGBgCgojIyMjI05vdyBub3JtYWxpemUgdGhlIGdlbmUgZXhwcmVzc2lvbiBtZWFzdXJlbWVudHMgZm9yIGVhY2ggY2VsbCBieSB0aGUgdG90YWwgZXhwcmVzc2lvbiAoc28gaXQgaXMgIyBvZiByZWFkcyBmb3IgdGhpcyBnZW5lIGRpdmlkZWQgYnkgblJlYWRzIGZvciB0aGF0IGNlbGwpLCBtdWx0aXBseSB0aGlzIGJ5IGEgc2NhbGUgZmFjdG9yICgxMCwwMDAgYnkgZGVmYXVsdCksIGxvZy10cmFuc2Zvcm0gKGxvZzFwKHgpLCB3aGljaCBpcyBsb2coMSt4KSkgdGhlIHJlc3VsdCwgYW5kIHRoZW4gc2F2ZSB0aGUgcmVzdWx0IGlzIGluIFNOcl9NYXJAZGF0YQoKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXkpCmBgYAoKIyMjIyNOb3cgc2NhbGUgdGhlIGRhdGE6IFRoZSBzY2FsZS5kYXRhIHNsb3QgKG9iamVjdEBzY2FsZS5kYXRhKSByZXByZXNlbnRzIGEgY2VsbOKAmXMgcmVsYXRpdmUgZXhwcmVzc2lvbiBvZiBlYWNoIGdlbmUsIGluIGNvbXBhcmlzb24gdG8gYWxsIG90aGVyIGNlbGxzLiBTbyB2YWx1ZSAwIGluIHRoZSBzY2FsZS5kYXRhIG1lYW5zIGF2ZXJhZ2UgZXhwcmVzc2lvbiBsZXZlbCBmb3IgdGhhdCBnZW5lIGFjcm9zcyBhbGwgY2VsbHMuIFRoZSBtb3JlIHBvc2l0aXZlLCB0aGUgaGlnaGVyIHRoYXQgZ2VuZSBpcyBleHByZXNzZWQgaW4gdGhhdCBjZWxsLiBUaGUgdmFsdWVzIGFyZSByZS1jZW50ZXJlZCBmb3IgZWFjaCBnZW5lLiBUaGlzIGRhdGEgaXMgdXNlZCBhcyBpbnB1dCBmb3IgZGltZW5zaW9uYWwgcmVkdWN0aW9uIHRlY2huaXF1ZXMsIGFuZCBpcyBkaXNwbGF5ZWQgaW4gaGVhdG1hcHMuCmBgYHtyfQojaWYgd2FudCB0byByZWdyZXNzIG91dCBzb21lIGZhY3RvcnMsIHVzZSBpbiB0aGUgU2NhbGVEYXRhIGZ1bmN0aW9uOiB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJuUmVhZHMiLCAicGVyY2VudC5lcmNjIiwiUm40NXMiLCJuR2VuZSIpCiNIZXJlIGxldCdzIG5vdCByZWdyZXNzIG91dCBhbnl0aGluZyBhbmQgdGFrZSBhIGxvb2sKc2V1VHJhY2hlYV9NYXkgPC0gU2NhbGVEYXRhKG9iamVjdCA9IHNldVRyYWNoZWFfTWF5KQpgYGAKCmBgYHtyfQpzZXVUcmFjaGVhX01heSA8LSBGaW5kVmFyaWFibGVHZW5lcyhvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZG8ucGxvdCA9IFRSVUUsIHguaGlnaC5jdXRvZmYgPSBJbmYsIHkuY3V0b2ZmID0gMC41KQpgYGAKIyMjIyNUaGUgYWJvdmUgZ2VuZXJhdHMgb2JqZWN0QHZhci5nZW5lcywgd2hpY2ggaXMgYSB2ZWN0b3Igb2YgZ2VuZSBuYW1lcyB0aGF0IGFyZSBpZGVudGlmaWVkIHRvIGJlIHZhcmlhYmxlLiB5LmN1dG9mZiBkZWNpZGVzIHRoZSBjdXRvZmYgZm9yIGJlaW5nICJ2YXJpYWJsZSIuCiMjIyMjI1RoZSByZXN1bHQgb2YgYWxsIGFuYWx5c2lzIGlzIHN0b3JlZCBpbiBvYmplY3RAaHZnLmluZm8uIEEgcGxvdCBpcyBhbHNvIGdlbmVyYXRlZCwgd2l0aCAidmFyaWFibGUiIGdlbmVzIGxhYmVsZWQgd2l0aCBuYW1lcy4KCiMjIyMjI3J1biBQQ0Egb24gdGhlIHNldCBvZiBnZW5lcyBkZWNpZGVkIGluIHNvX1NOckB2YXIuZ2VuZXM6CiMjIyMjI1JldHVybnMgU2V1cmF0IG9iamVjdCB3aXRoIHRoZSBQQ0EgY2FsY3VsYXRpb24gc3RvcmVkIGluIG9iamVjdEBkciRwY2EuIEluIHRoZSBmdW5jdGlvbiBiZWxvdywgaWYgZG8ucHJpbnQ9VFJVRSwgZ2VuZXMgaW4gZWFjaCBQQyB3aWxsIGJlIHNob3duLgpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gUnVuUENBKG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBkby5wcmludCA9IEZBTFNFKQpQQ0FQbG90KHNldVRyYWNoZWFfTWF5KQpgYGAKIyMjIyNQcm9qZWN0UENBIHNjb3JlcyBlYWNoIGdlbmUgaW4gdGhlIGRhdGFzZXQgKGluY2x1ZGluZyBnZW5lcyBub3QgaW5jbHVkZWQgaW4gdGhlIFBDQSkgYmFzZWQgb24gdGhlaXIgY29ycmVsYXRpb24gd2l0aCB0aGUgY2FsY3VsYXRlZCBjb21wb25lbnRzLiBUaG91Z2ggd2UgZG9u4oCZdCB1c2UgdGhpcyBmdXJ0aGVyIGhlcmUsIGl0IGNhbiBiZSB1c2VkIHRvIGlkZW50aWZ5IG1hcmtlcnMgdGhhdCBhcmUgc3Ryb25nbHkgY29ycmVsYXRlZCB3aXRoIGNlbGx1bGFyIGhldGVyb2dlbmVpdHksIGJ1dCBtYXkgbm90IGhhdmUgcGFzc2VkIHRocm91Z2ggdmFyaWFibGUgZ2VuZSBzZWxlY3Rpb24uIFRoZSByZXN1bHRzIG9mIHRoZSBwcm9qZWN0ZWQgUENBIGNhbiBiZSBleHBsb3JlZCBieSBzZXR0aW5nIHVzZS5mdWxsPVQgaW4gdGhlIGZ1bmN0aW9ucyBiZWxvdy4KYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIFByb2plY3RQQ0Eob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGRvLnByaW50ID0gVFJVRSkKYGBgCiMjIyMjQW5vdGhlciB3YXkgdG8gc2hvdyBtYWpvciBnZW5lcyBpbiBtYWpvciBQQ3M6CmBgYHtyfQpQcmludFBDQShzZXVUcmFjaGVhX01heSwgcGNzLnByaW50ID0gMTo1LCBnZW5lcy5wcmludCA9IDUsIHVzZS5mdWxsID0gVFJVRSkKYGBgCiMjIyMjQmVsb3cgaXMgYW5vdGhlciB3YXkgdG8gc2VlIFBDcyBhbmQgaG93IHRoZXkgc2VwYXJhdGUgdGhlIGRhdGE6IGNlbGxzIGFuZCBnZW5lcyBhcmUgb3JkZXJlZCBhY2NvcmRpbmcgdG8gdGhlaXIgUENBIHNjb3Jlcy4gU2V0dGluZyBjZWxscy51c2UgKGZvciBleGFtcGxlOiBjZWxsLnVzZT0xMDApIHRvIGEgbnVtYmVyIHBsb3RzIHRoZSDigJhleHRyZW1l4oCZIGNlbGxzIG9uIGJvdGggZW5kcyBvZiB0aGUgc3BlY3RydW0sIHdoaWNoIGRyYW1hdGljYWxseSBzcGVlZHMgcGxvdHRpbmcgZm9yIGxhcmdlIGRhdGFzZXRzIChidXQgd2lsbCBpZ25vcmUgdGhlIGNlbGxzIGluIHRoZSBtaWRkbGUpLiBudW0uZ2VuZXM9MzAgYnkgZGVmYXVsdC4KYGBge3J9ClBDSGVhdG1hcChvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgcGMudXNlID0gMTozLCBkby5iYWxhbmNlZCA9IFRSVUUsIGxhYmVsLmNvbHVtbnMgPSBGQUxTRSkKYGBgCiMjIyMjTm93IG5lZWQgdG8gZGVjaWRlIGhvdyBtYW55IFBDcyB0byB1c2U6CmBgYHtyfQpQQ0VsYm93UGxvdChvYmplY3QgPSBzZXVUcmFjaGVhX01heSkKYGBgCiMjIyMjI1RoZSBhYm92ZSBwbG90IHNob3dzIHRoYXQgdGhlIGVsYm93IG9mIHRoZSBncmFwaCBmYWxscyBhdCBhcm91bmQgcGMgMjAuCiMjIyMjI0Fub3RoZXIgd2F5IHRvIHN0YXRpc3RpY2FsbHkgZXN0aW1hdGU6IChjYXV0aW9uOiBydW5uaW5nIHRoaXMgaXMgc2xvdykKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIEphY2tTdHJhdyhzZXVUcmFjaGVhX01heSwgbnVtLnJlcGxpY2F0ZSA9IDEwMCwgZG8ucHJpbnQgPSBGQUxTRSkKSmFja1N0cmF3UGxvdChzZXVUcmFjaGVhX01heSwgUENzID0gMToyMCkKYGBgCgpgYGB7cn0Kbi5wY3MgPSAyMApgYGAKIyMjIyNyZXNvbHV0aW9uIHBhcmFtZXRlciBzZXRzIHRoZSDigJhncmFudWxhcml0eeKAmSBvZiB0aGUgZG93bnN0cmVhbSBjbHVzdGVyaW5nLCB3aXRoIGluY3JlYXNlZCB2YWx1ZXMgbGVhZGluZyB0byBhIGdyZWF0ZXIgbnVtYmVyIG9mIGNsdXN0ZXJzLiAKYGBge3J9CnJlcy51c2VkIDwtIDEKYGBgCiMjIyMjSy1uZWFyZXN0IG5laWdoYm9yOiAKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIEZpbmRDbHVzdGVycyhvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgcmVkdWN0aW9uLnR5cGUgPSAicGNhIiwgZGltcy51c2UgPSAxOm4ucGNzLCAKICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbiA9IHJlcy51c2VkLCBwcmludC5vdXRwdXQgPSAwLCBmb3JjZS5yZWNhbGMgPSBUKQpgYGAKIyMjIyNMZXQncyBleHRyYWN0IHBsYXRlIGFuZCBpbmRleCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBjZWxsIG5hbWVzIChjb2x1bW4gbmFtZXMpIGFuZCBtYWtlIHRoZW0gcGFydCBvZiB0aGUgbWV0YSBkYXRhCmBgYHtyfQpjZWxsX25hbWU8LXJlYWQudGFibGUodGV4dD1uYW1lcyhzZXVUcmFjaGVhX01heUBpZGVudCksc2VwPSJfIixjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpCnRhYmxlKGNlbGxfbmFtZVssMV0pCmNvbG5hbWVzKGNlbGxfbmFtZSk8LWMoInBsYXRlIiwid2VsbCIsInRpc3N1ZSIsIm90aGVyIikKYGBgCiMjIyMjTm93IEkgY2FuIHNlZSBob3cgbWFueSBjZWxsIHBhc3NpbmcgZmlsdGVycyBmcm9tIGVhY2ggcGxhdGUuCgojIyMjI05vdyBsZXQncyBtYWtlIHRoZSAicGxhdGUiIGluZm9ybWF0aW9uIHBhcnQgb2YgZWFjaCBjZWxsJ3MgbWV0YWRhdGE6CmBgYHtyfQpwbGF0ZTwtY2VsbF9uYW1lJHBsYXRlCm5hbWVzKHBsYXRlKTwtbmFtZXMoc2V1VHJhY2hlYV9NYXlAaWRlbnQpICAgI0FkZE1ldGFEYXRhIG5lZWRzIG5hbWVzIHRvIGFzc2lnbiB2YWx1ZXMKc2V1VHJhY2hlYV9NYXk8LUFkZE1ldGFEYXRhKG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBtZXRhZGF0YSA9IHBsYXRlLCBjb2wubmFtZSA9ICJwbGF0ZSIpCmBgYAoKIyMjIyN0U05FOiAocGVycGxleGl0eSBkZWZhdWx0IGlzIDMwKQpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gUnVuVFNORShvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZGltcy51c2UgPSAxOm4ucGNzLCBwZXJwbGV4aXR5PTMwKQpgYGAKYGBge3J9ClRTTkVQbG90KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBkby5sYWJlbCA9IFQpCmBgYAoKYGBge3J9ClRTTkVQbG90KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBncm91cC5ieT0icGxhdGUiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CkZlYXR1cmVQbG90KHNldVRyYWNoZWFfTWF5LCBjKCJuR2VuZSIsIkdmcF90cmFuc2dlbmUiLCJUZHRvbV90cmFuc2dlbmUiLCJTaGgiLCJBbm8xIiwiRXBjYW0iLCJMdW0iLCJBdXJrYiIsIk1hdG40IiwiRXNhbSIsIkFjdGMxIiwiUGF4OCIpLCBwdC5zaXplID0gMC45LCBuQ29sID0gMyxuby5sZWdlbmQgPSBGKQpgYGAKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIFNldEFsbElkZW50KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBpZCA9ICJpZGVudCIpCmBgYAoKYGBge3J9CkdlbmVQbG90KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBnZW5lMSA9ICJTaGgiLCBnZW5lMiA9ICJHZnBfdHJhbnNnZW5lIiwgdXNlLnJhdz1UKQpgYGAKYGBge3IsZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9ClZsblBsb3Qob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGZlYXR1cmVzLnBsb3QgPSBjKCJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwgIkNyZV90cmFuc2dlbmUiKSwgbkNvbCA9IDMpCmBgYAoKCmBgYHtyfQpEb0hlYXRtYXAob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGdlbmVzLnVzZSA9IGMoIlRkdG9tX3RyYW5zZ2VuZSIsIkNyZV90cmFuc2dlbmUiLCAiR2ZwX3RyYW5zZ2VuZSIsIlNoaCIsIkFubzEiLCJTb3g5IiksIAogICAgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCBncm91cC5sYWJlbC5yb3QgPSBUUlVFKQpgYGAKCiMjIyMjZmluZCBtYXJrZXJzIGZvciBldmVyeSBjbHVzdGVyIGNvbXBhcmVkIHRvIGFsbCByZW1haW5pbmcgY2VsbHMsIHJlcG9ydCBvbmx5IHRoZSBwb3NpdGl2ZSBvbmVzCmBgYHtyfQpjbHVzdGVyLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMob2JqZWN0PXNldVRyYWNoZWFfTWF5LCBtaW4ucGN0ID0gMC4yLG9ubHkucG9zPVRSVUUpCmNsdXN0ZXIubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKDEwLCBhdmdfbG9nRkMpCmBgYAojIyMjI2NvbXBhcmUgY2x1c3RlciAwIGFuZCAyCmBgYHtyfQpjbHVzdGVyMC5tYXJrZXJzLnBvcyA8LSBGaW5kTWFya2VycyhzZXVUcmFjaGVhX01heSwgaWRlbnQuMSA9IDAsaWRlbnQuMiA9IDIsIG1pbi5wY3QgPSAwLG9ubHkucG9zPVRSVUUpCnByaW50KGNsdXN0ZXIwLm1hcmtlcnMucG9zKQpgYGAKYGBge3J9CmNsdXN0ZXIyLm1hcmtlcnMucG9zIDwtIEZpbmRNYXJrZXJzKHNldVRyYWNoZWFfTWF5LCBpZGVudC4xID0gMixpZGVudC4yID0gMCwgbWluLnBjdCA9IDAsb25seS5wb3M9VFJVRSkKcHJpbnQoY2x1c3RlcjIubWFya2Vycy5wb3MpCmBgYAoKIyMjIyNzYXZlIHRoZSBzZXVyYXQgcHJvamVjdCBmb3IgZnV0dXJlIHZpc2l0OgpgYGB7cn0Kc2F2ZShzZXVUcmFjaGVhX01heSxmaWxlPSJzZXVyYXRfVHJhY2hlYV9NYXkuUkRhdGEiKQpsb2FkKCJzZXVyYXRfVHJhY2hlYV9NYXkuUkRhdGEiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CkZlYXR1cmVQbG90KHNldVRyYWNoZWFfTWF5LCBjKCJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwiVHJwbTUiLCJBbm8xIiwiQW5vNyIsIlBsY2IyIiwiSWwyNSIsIkRiaCIsIlNveDkiKSwgcHQuc2l6ZSA9IDAuNiwgbkNvbCA9IDMsbm8ubGVnZW5kID0gRikKYGBgCmBgYHtyLGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyfQpWbG5QbG90KG9iamVjdCA9IHNldVRyYWNoZWFfSnVuLCBmZWF0dXJlcy5wbG90ID0gYygiR2ZwX3RyYW5zZ2VuZSIsIlRkdG9tX3RyYW5zZ2VuZSIpLCBuQ29sID0gMSx4LmxhYi5yb3QgPSBUUlVFKQpgYGAKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTE0fQpEb0hlYXRtYXAob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGdlbmVzLnVzZSA9IGMoICJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwiRXBjYW0iLCJDcmVfdHJhbnNnZW5lIiksIAogICAgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCBncm91cC5sYWJlbC5yb3QgPSBUUlVFKQpgYGAKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTE0fQpEb0hlYXRtYXAob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGdlbmVzLnVzZSA9IGMoICJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwiRXBjYW0iLCJDcmVfdHJhbnNnZW5lIiksIAogICAgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCBncm91cC5sYWJlbC5yb3QgPSBUUlVFLHVzZS5zY2FsZWQgPSBGKQpgYGAKCiMjIyMgTWFwIHNvcnRpbmcgZGF0YSB0byBzZXF1ZW5jaW5nIGRhdGE6CiMjIyMjUmVhZCBpbmRleCBkYXRhOgpgYGB7cn0KQjAwMzkzODwtcmVhZC5jc3YoZmlsZT0iVHJhY2hlYV9CMDAzOTM4LmNzdiIsaGVhZGVyPVRSVUUsc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzID0gRikKQjAwMzkzOF9zb3J0PC1CMDAzOTM4W0IwMDM5MzgkSW5kZXghPSIiLF0KQjAwMzkzNTwtcmVhZC5jc3YoZmlsZT0iVHJhY2hlYV9CMDAzOTM1LmNzdiIsaGVhZGVyPVRSVUUsc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzID0gRikKQjAwMzkzNV9zb3J0PC1CMDAzOTM1W0IwMDM5MzUkSW5kZXghPSIiLF0KYGBgCgojIyMjI0V4dHJhY3QgZXhwcmVzc2lvbiBsZXZlbHMgb2YgZ2VuZXMuIE1ha2UgYSBkYXRhZnJhbWUgKGNsdXN0ZXJfY2VsbCkgdGhhdCBoYXMgdGhlIHBsYXRlICMsIGluZGV4IywgY2x1c3RlciBpZGVudGl0eSwgYW5kIGV4cHJlc3Npb24gbGV2ZWxzIG9mIHNvbWUgZ2VuZXMKYGBge3J9ClRkdG9tYXRvPC1zZXVUcmFjaGVhX01heUBkYXRhW3doaWNoKHJvd25hbWVzKHNldVRyYWNoZWFfTWF5QGRhdGEpPT0iVGR0b21fdHJhbnNnZW5lIiksXQpHZnA8LXNldVRyYWNoZWFfTWF5QGRhdGFbd2hpY2gocm93bmFtZXMoc2V1VHJhY2hlYV9NYXlAZGF0YSk9PSJHZnBfdHJhbnNnZW5lIiksXQpjbHVzdGVyX2NlbGw8LWNiaW5kKGNlbGxfbmFtZVssMToyXSxzZXVUcmFjaGVhX01heUBpZGVudCxUZHRvbWF0byxHZnApCmNvbG5hbWVzKGNsdXN0ZXJfY2VsbCk8LWMoInBsYXRlIiwiSW5kZXgiLCJpZGVudGl0eSIsIlRkdG9tX3RyYW5zZ2VuZSIsIkdmcF90cmFuc2dlbmUiKQpgYGAKCiMjIyMjI3NwZWNpZnkgcGxhdGUjIGluIHNvcnRpbmcgbWV0YWRhdGEKYGBge3J9CkIwMDM5MzVfc29ydCRwbGF0ZTwtcmVwKCJCMDAzOTM1IiwzNTIpCiNtZXJnZV9CMDAzOTM1PC1tZXJnZShjbHVzdGVyX2NlbGwsQjAwMzkzNV9zb3J0KQpgYGAKCmBgYHtyfQojbG93UV9CMDAzOTM1IDwtIGFudGlfam9pbihCMDAzOTM1X3NvcnQsY2x1c3Rlcl9jZWxsLGJ5PWMoInBsYXRlIiwiSW5kZXgiKSkKYGBgCgpgYGB7cn0Kam9pbl9CMDAzOTM1PC1sZWZ0X2pvaW4oQjAwMzkzNV9zb3J0LGNsdXN0ZXJfY2VsbCkKYGBgCmBgYHtyfQp0YWJsZShqb2luX0IwMDM5MzUkaWRlbnRpdHksZXhjbHVkZT1OVUxMKQpgYGAKIyMjIyMjIE5BIGluIHRoZSBpZGVudGl0eSBjb2x1bW4gbWVhbnMgdGhvc2UgImNlbGxzIiBkaWQgbm90IHBhc3MgdGhlIGZpbHRlcmluZyBjcml0ZXJpYSBhYm92ZSAobkdlbmUgNTAwLCBuUmVhZHMgMTAwayBldGMuLikKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzUsYWVzKHg9bG9nMTAoSG9lY2hzdC4zMzM0Mi5BLkNvbXBlbnNhdGVkKSkpK2dlb21fZGVuc2l0eShhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKIyMjIyMjIFNvIHRob3NlIEhvZWNoc3Qgc3VwZXIgaGlnaCBqdW5rIHRlbmQgdG8gaGF2ZSBpbnRlcm1lZGlhdGUtaGlnaCBsZXZlbCBvZiBFR0ZQOgpgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzNSxhZXMoeD1sb2cxMChIb2VjaHN0LjMzMzQyLkEuQ29tcGVuc2F0ZWQpLHk9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCiMjIyMjIyBBbmQgdGhlIEhvZWNoc3Qgc3VwZXIgaGlnaCBqdW5rIHRlbmQgdG8gaGF2ZSByZWxhdGl2ZWx5IGxvdyB0ZFRvbWF0byBzaWduYWw6CmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyh4PWxvZzEwKEhvZWNoc3QuMzMzNDIuQS5Db21wZW5zYXRlZCkseT1sb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyh4PWxvZzEwKEVHRlAuQS5Db21wZW5zYXRlZCkseT1sb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSxzaXplPTAuMikKYGBgCiMjIyMjIyBBbmQgdGhlIE5BICJjZWxscyIiIHRlbmRzIHRvIGJlIHZlcnkgc21hbGwgaW4gdGVybXMgb2YgRlNDLlc6CmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyhsb2cxMChFR0ZQLkEuQ29tcGVuc2F0ZWQpLEZTQy5XKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzUsYWVzKGxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpLEZTQy5XKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyhGU0MuQSxsb2cxMChCU0MuQSkpKStnZW9tX3BvaW50KGFlcyhjb2xvcj1pZGVudGl0eSkpCmBgYApgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzNSxhZXMoRlNDLkEsbG9nMTAoSG9lY2hzdC4zMzM0Mi5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoc3Vic2V0KGpvaW5fQjAwMzkzNSwhaXMubmEoR2ZwX3RyYW5zZ2VuZSkpLGFlcyh4PWxvZzEwKEVHRlAuQS5Db21wZW5zYXRlZCkseT1sb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSxjb2xvcj1HZnBfdHJhbnNnZW5lKSkrZ2VvbV9wb2ludChzaXplPTAuMykrc2NhbGVfY29sb3JfY29udGludW91cyhsb3c9InllbGxvdyIsaGlnaD0iQmxhY2siKQpgYGAKYGBge3J9CmdncGxvdChzdWJzZXQoam9pbl9CMDAzOTM1LCFpcy5uYShUZHRvbV90cmFuc2dlbmUpKSxhZXMoeD1sb2cxMChFR0ZQLkEuQ29tcGVuc2F0ZWQpLHk9bG9nMTAodGRUb21hdG8uQS5Db21wZW5zYXRlZCksY29sb3I9VGR0b21fdHJhbnNnZW5lKSkrZ2VvbV9wb2ludChzaXplPTAuMykrc2NhbGVfY29sb3JfY29udGludW91cyhsb3c9IkJsYWNrIixoaWdoPSJ5ZWxsb3ciKQpgYGAKYGBge3J9CmdncGxvdChzdWJzZXQoam9pbl9CMDAzOTM1LCFpcy5uYShUZHRvbV90cmFuc2dlbmUpKSxhZXMoeD1sb2cxMChFR0ZQLkEuQ29tcGVuc2F0ZWQpLHk9bG9nMTAodGRUb21hdG8uQS5Db21wZW5zYXRlZCksY29sb3I9bG9nKFRkdG9tX3RyYW5zZ2VuZS9HZnBfdHJhbnNnZW5lKSkpK2dlb21fcG9pbnQoc2l6ZT0wLjMpK3NjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93PSJCbGFjayIsaGlnaD0ieWVsbG93IikKYGBgCgojIyMjIyMgSW5zdGVyZXN0aW5nbHkgY2x1c3RlciAwIGFuZCAyIG1heSBkaWZmZXIgYSBiaXQgaW4gc2l6ZXMKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzVbam9pbl9CMDAzOTM1JGlkZW50aXR5ICVpbiUgYygiMCIsIjIiKSxdLGFlcyhGU0MuVykpK2dlb21fZGVuc2l0eShhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKCmBgYHtyfQpCMDAzOTM4X3NvcnQkcGxhdGU8LXJlcCgiQjAwMzkzOCIsMzUyKQpqb2luX0IwMDM5Mzg8LWxlZnRfam9pbihCMDAzOTM4X3NvcnQsY2x1c3Rlcl9jZWxsKQpgYGAKYGBge3J9CnRhYmxlKGpvaW5fQjAwMzkzOCRpZGVudGl0eSxleGNsdWRlPU5VTEwpCmBgYAojIyMjIyMgSW50ZXJtZWRpYXRlIEhvZWNoc3QgYW5kIGJlbG93IHdlcmUgY3V0IG9mZi4gSG9lY2hzdCBzdXBlciBoaWdoIHdlcmUgc29ydGVkLiBUaGVyZWZvcmUgd2UgZ290IHNvIG1hbnkgTkEgaW4gQjAwMzkzOApgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzOCxhZXMobG9nMTAoSG9lY2hzdC4zMzM0Mi5BLkNvbXBlbnNhdGVkKSkpK2dlb21fZGVuc2l0eShhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKIyMjIyMjIEFnYWluIHRob3NlIEhvZWNoc3QgaGlnaCBqdW5rIGlzIHNtYWxsIGluIHNpemUKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzgsYWVzKHg9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSx5PWxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpLHNpemU9MC4yKQpgYGAKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzgsYWVzKHg9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSx5PWxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpLGNvbG9yPUdmcF90cmFuc2dlbmUpKStnZW9tX3BvaW50KHNpemU9MC4zKStzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdz0ieWVsbG93IixoaWdoPSJyZWQiKQpgYGAKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzgsYWVzKHg9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSx5PWxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpLGNvbG9yPVRkdG9tX3RyYW5zZ2VuZSkpK2dlb21fcG9pbnQoc2l6ZT0wLjMpK3NjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93PSJ5ZWxsb3ciLGhpZ2g9InJlZCIpCmBgYApgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzOCxhZXMobG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSxGU0MuVykpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM4LGFlcyhsb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSxGU0MuVykpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM4LGFlcyhGU0MuQSxsb2cxMChIb2VjaHN0LjMzMzQyLkEuQ29tcGVuc2F0ZWQpKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKCgoKCgoKCgoKCgoK